/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年7月31日
 */
package com.massyframework.beanskin.runtime.service.adapt;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

import com.massyframework.beanskin.ModuleEventAdapter;
import com.massyframework.beanskin.service.ServiceReference;
import com.massyframework.beanskin.service.ServiceRepository;
import com.massyframework.beanskin.service.ServiceTrackerCustomizer;
import com.massyframework.beanskin.service.adapt.AdaptObjectFactory;
import com.massyframework.beanskin.service.adapt.AdaptObjectFactoryRepository;

/**
 * 适配对象工厂资源库
 * @author huangkh
 *
 */
@SuppressWarnings("rawtypes")
class AdaptObjectFactoryTracker extends ModuleEventAdapter
	implements AdaptObjectFactoryRepository,
		ServiceTrackerCustomizer<AdaptObjectFactory>{
	
	/* map:<AdaptType, map<HostType, List<AdaptObjectFactory>>> */
	private Map<Class<?>, Map<Class<?>, List<AdaptObjectFactory<?>>>> factoryMap;
	
	/* map:<HostImplType, map<adaptType, List<AdaptObjectFactory>> */
	private Map<Class<?>, Map<Class<?>, List>> cacheMap;
	
	/**
	 * 构造方法
	 */
	public AdaptObjectFactoryTracker() {
		this.factoryMap = new ConcurrentHashMap<>();
		this.cacheMap = new ConcurrentHashMap<>();
	}
	
	@Override
	public Set<Class<?>> getAdaptTypes(Class<?> hostType) {
		Set<Class<?>> result = new HashSet<>();
		for (Map.Entry<Class<?>, Map<Class<?>, List<AdaptObjectFactory<?>>>> entry: this.factoryMap.entrySet()) {
			for (Class<?> type: entry.getValue().keySet()) {
				if (type.isAssignableFrom(hostType)) {
					result.add(entry.getKey());
				}
			}
		}
		return result;
	}



	@SuppressWarnings({"unchecked" })
	@Override
	public <A> List<AdaptObjectFactory<A>> getAdaptObjectFactories(Class<A> adaptType,
			Class<?> hostType) {
		Map<Class<?>, List> map = this.cacheMap.computeIfAbsent(hostType,
				key -> new ConcurrentHashMap<Class<?>, List>());
		List result = map.computeIfAbsent(adaptType,
				key -> this.foundAdaptObjectFactoryies(hostType, adaptType));
		return (List<AdaptObjectFactory<A>>) result;
	}

	/**
	 * 发现已注册的AdaptObjectFactory
	 * @param hostType
	 * @param adaptType
	 * @return
	 */
	protected List<AdaptObjectFactory<?>> foundAdaptObjectFactoryies(Class<?> hostType, Class<?> adaptType){
		Map<Class<?>, List<AdaptObjectFactory<?>>> map = factoryMap.get(adaptType);
		if (map == null) return  Collections.emptyList();
		
		List<AdaptObjectFactory<?>> result = new ArrayList<>();
		for (Map.Entry<Class<?>, List<AdaptObjectFactory<?>>> entry: map.entrySet()) {
			if (entry.getKey().isAssignableFrom(hostType)) {
				result.addAll(entry.getValue());
			}
		}
		
		return result;
	}

	@Override
	public AdaptObjectFactory<?> addService(ServiceReference<AdaptObjectFactory> reference, ServiceRepository repository) {
		AdaptObjectFactory<?> result = repository.getService(reference).orElse(null);
		if (result != null) {
			Class<?> adaptType = result.supportAdaptObject();
			Class<?> hostType = result.getHostType();
			
			Map<Class<?>, List<AdaptObjectFactory<?>>> map = this.factoryMap.computeIfAbsent(adaptType, 
					key-> new ConcurrentHashMap<Class<?>, List<AdaptObjectFactory<?>>>());
			
			List<AdaptObjectFactory<?>> list = map.computeIfAbsent(hostType, key-> new CopyOnWriteArrayList<>());
			list.add(result);
			this.onChanged(result);
		}
		return result;
	}

	@Override
	public void removeService(ServiceReference<AdaptObjectFactory> reference, AdaptObjectFactory service) {
		Map<Class<?>, List<AdaptObjectFactory<?>>> map = this.factoryMap.get(service.supportAdaptObject());
		if (map != null) {
			List<AdaptObjectFactory<?>> list= map.get(service.getHostType());
			if (list != null) {
				list.remove(service);
			}
		}
	}
	
	public void clearAll() {
		this.cacheMap.clear();
		this.factoryMap.clear();
	}
	
	/**
	 * 清除所有指定类加载器的类
	 * @param classLoader
	 */
	public void clearClassLoader(ClassLoader classLoader) {
		Map<Class<?>, List<Class<?>>> founds = new HashMap<>();
		
		for (Map.Entry<Class<?>, Map<Class<?>, List<AdaptObjectFactory<?>>>> entry: this.factoryMap.entrySet()) {
			if (entry.getClass().getClassLoader() == classLoader) {
				founds.put(entry.getClass(), null);
				continue;
			}
			
			List<Class<?>> list = null;
			for (Class<?> type: entry.getValue().keySet()) {
				if (type.getClassLoader() == classLoader) {
					if (list == null) {
						list = new ArrayList<>();
					}
					
					list.add(type);
				}
			}
			if (list != null) {
				founds.put(entry.getClass(), list);
			}
		}
		
		//移除所有类和适配工厂实例
		List<AdaptObjectFactory<?>> factories = new ArrayList<>();
		for (Map.Entry<Class<?>, List<Class<?>>> entry: founds.entrySet()) {
			if (entry.getValue() == null) {
				//全部删除
				
				Map<Class<?>, List<AdaptObjectFactory<?>>> map =
						this.factoryMap.remove(entry.getKey());
				for (List<AdaptObjectFactory<?>> list: map.values()) {
					factories.addAll(list);
				}
			}else {
				Map<Class<?>, List<AdaptObjectFactory<?>>> map =
						this.factoryMap.get(entry.getKey());
				for (Class<?> type: entry.getValue()) {
					List<AdaptObjectFactory<?>> list = map.remove(type);
					factories.addAll(list);
				}
			}
		}
		
		//清除缓存
		for (AdaptObjectFactory<?> factory: factories) {
			this.onChanged(factory);
		}
	}
	
	/**
	 * 添加/移除适配对象工厂的后续处理
	 * @param factory {@link AdaptObjectFactory}
	 */
	protected void onChanged(AdaptObjectFactory<?> factory) {
		Class<?> hostType = factory.getHostType();
		List<Class<?>> subTypes =this.foundSubTypesWithCacheMap(hostType);
		this.clearCacheMap(subTypes);
	}
	
	/**
	 * 在cacheMap中查找{@code hostType}的所有子类 
	 * @param hostType {@link Class}
	 * @return {@link List}
	 */
	protected List<Class<?>> foundSubTypesWithCacheMap(Class<?> hostType){
		return this.cacheMap.keySet().stream()
					.filter( type -> hostType.isAssignableFrom(type))
					.collect(Collectors.toList());
	}
	
	/**
	 * 清除cahcheMap中指定的hostType映射记录
	 * @param subTypes {@link List}
	 */
	protected void clearCacheMap(List<Class<?>> subTypes) {
		for (Class<?> subType: subTypes) {
			this.cacheMap.remove(subType);
		}
	}
}
